﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraReports.UI;
using System.Data;
using DevExpress.XtraCharts;
using System.Drawing;

namespace ZX.Report
{
    /// <summary>
    /// 图表报表类
    /// </summary>
    public class ChartReport : ReportFactory
    {
        private ChartReport(ParamsFactory paramsFactory)
        {
            this.paramsFactory = paramsFactory;
        }
        /// <summary>
        /// 图表报表实例化
        /// </summary>
        /// <param name="paramsFactory">报表参数</param>
        /// <returns></returns>
        public new static ChartReport GetInstance(ParamsFactory paramsFactory)
        {
            return new ChartReport(paramsFactory);
        }
        /// <summary>
        /// 获取报表
        /// </summary>
        /// <returns></returns>
        public override XtraReport GetReport()
        {
            XtraReport rpt = new XtraReport();// 建立报表实例
            DetailBand detail = new DetailBand();
            PageHeaderBand pageHeader = new PageHeaderBand();
            ReportFooterBand reportFooter = new ReportFooterBand();
            detail.Height = 200;
            reportFooter.Height = 50;
            pageHeader.Height = 50;
            rpt.Bands.AddRange(new Band[] { detail, pageHeader, reportFooter });
            //设置Series
            DataSet ds = this.paramsFactory.reportDataSource;
            ChartParams chartparams = (ChartParams)this.paramsFactory;
            rpt.PaperKind = chartparams.pagerSize;
            foreach (DataTable dt in ds.Tables)
            {
                XRChart chart = new XRChart();
                ChartTitle title = new ChartTitle();
                int key = int.Parse(dt.TableName);
                title.Text = chartparams.Title[key];
                chart.Titles.Add(title);
                chart.WidthF = chartparams.Width[key] > 0 ? chartparams.Width[key] : 600;
                chart.HeightF = chartparams.Height[key] > 0 ? chartparams.Height[key] : 400;
                chart.Legend.AlignmentHorizontal = LegendAlignmentHorizontal.Right;//右上角文字位置
                chart.Legend.AlignmentVertical = LegendAlignmentVertical.Top;
                chart.PaletteBaseColorNumber = 2;
                chart.PaletteName = "Verve";
                int hspace = 150;
                int wspace = 5;
                int[] w = new int[10];//最多支持10个图表
                int[] h = new int[10];
                for (int i = 0; i < 10; i++)
                {
                    if (chartparams.Width.ContainsKey(i + 1))
                    {
                        w[i] = chartparams.Width[i + 1];
                    }
                    else
                    {
                        w[i] = 600;
                    }
                    if (chartparams.Height.ContainsKey(i + 1))
                    {
                        h[i] = chartparams.Height[i + 1];
                    }
                    else
                    {
                        h[i] = 300;
                    }
                }
                switch (key)
                {
                    case 1:
                        chart.LocationF = new PointF(0, 0);
                        break;
                    case 2:
                        chart.LocationF = new PointF(w[0] + wspace, 0);
                        break;
                    case 3:
                        int H3 = h[0];
                        if (H3 < h[1]) H3 = h[1];
                        chart.LocationF = new PointF(0, H3 + hspace);
                        break;
                    case 4:
                        int W4 = w[0];
                        if (W4 < w[2]) W4 = w[2];
                        int H4 = h[0];
                        if (H4 < h[1]) H4 = h[1];
                        chart.LocationF = new PointF(W4 + wspace, H4 + hspace);
                        break;
                    case 5:
                        int H5 = (h[0] + h[2]) > (h[1] + h[3]) ? (h[0] + h[2]) : (h[1] + h[3]) + hspace;
                        chart.LocationF = new PointF(0, H5 + hspace);
                        break;
                    case 6:
                        int H6 = (h[0] + h[2]) > (h[1] + h[3]) ? (h[0] + h[2]) : (h[1] + h[3]) + hspace;
                        int W6 = Math.Max(Math.Max(h[0], h[2]), h[4]);
                        chart.LocationF = new PointF(W6 + wspace, H6 + hspace);
                        break;
                    case 7:
                        int H7 = Math.Max(h[0] + h[2] + h[4], h[1] + h[3] + h[5]) + 2 * hspace;
                        chart.LocationF = new PointF(0, H7 + hspace);
                        break;
                    case 8:
                        int H8 = Math.Max(h[0] + h[2] + h[4], h[1] + h[3] + h[5]) + 2 * hspace;
                        int[] temp8 = { h[0], h[2], h[4], h[6] };
                        int W8 = temp8.Max();
                        chart.LocationF = new PointF(W8 + wspace, H8 + hspace);
                        break;
                    case 9:
                        int H9 = Math.Max(h[0] + h[2] + h[4] + h[6], h[1] + h[3] + h[5] + h[7]) + 3 * hspace;
                        chart.LocationF = new PointF(0, H9 + hspace);
                        break;
                    case 10:
                        int H10 = Math.Max(h[0] + h[2] + h[4] + h[6], h[1] + h[3] + h[5] + h[7]) + 3 * hspace;
                        int[] temp10 = { h[0], h[2], h[4], h[6], h[8] };
                        int W10 = temp10.Max();
                        chart.LocationF = new PointF(W10 + wspace, H10 + hspace);
                        break;
                }
                ViewType viewType = ViewType.Bar;
                switch (chartparams.ChartViewType[key].ToLower())
                {
                    case "bar"://柱状
                        viewType = ViewType.Bar;
                        break;
                    case "pie"://饼状
                        viewType = ViewType.Pie;
                        break;
                    case "line"://点线
                        viewType = ViewType.Line;
                        break;
                    case "funnel"://漏斗
                        viewType = ViewType.Funnel;
                        break;
                    case "splinearea"://区域
                        viewType = ViewType.SplineArea;
                        break;
                }
                
                if (dt.Columns.Count > 1 && dt.Rows.Count>0)
                {
                    int xytype = 0;
                    try
                    {
                        xytype = chartparams.XYType[key];
                    }
                    catch { }
                    if (viewType != ViewType.Bar)
                    {
                        xytype = 0;
                    }
                    if (xytype == 0)
                    {
                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            SeriesPoint[] seriesPosts = new SeriesPoint[dt.Columns.Count - 1];
                            double[] yy = new double[dt.Columns.Count - 1];
                            try
                            {
                                for (int j = 1; j < dt.Columns.Count; j++)
                                {
                                    yy[j - 1] = double.Parse(dt.Rows[i][j].ToString());
                                    double[] tempY = new double[1];
                                    tempY[0] = yy[j - 1];
                                    seriesPosts[j - 1] = new SeriesPoint(dt.Columns[j].Caption, tempY);
                                }
                            }
                            catch { }
                            chart.Series.Add(dt.Rows[i][0].ToString(), viewType);
                            chart.Series[i].LegendPointOptions.PointView = PointView.Argument;
                            chart.Series[i].Points.AddRange(seriesPosts);
                        }
                    }
                    else
                    {
                        for (int i = 1; i < dt.Columns.Count; i++)
                        {
                            SeriesPoint[] seriesPosts = new SeriesPoint[dt.Rows.Count];
                            double[] yy = new double[dt.Rows.Count];
                            try
                            {
                                for (int j = 0; j < dt.Rows.Count; j++)
                                {
                                    yy[j] = double.Parse(dt.Rows[j][i].ToString());
                                    double[] tempY = new double[1];
                                    tempY[0] = yy[j];
                                    seriesPosts[j] = new SeriesPoint(dt.Rows[j][0].ToString(), tempY);
                                }
                            }
                            catch { }
                            chart.Series.Add(dt.Columns[i].Caption, viewType);
                            chart.Series[i-1].LegendPointOptions.PointView = PointView.Argument;
                            chart.Series[i-1].Points.AddRange(seriesPosts);
                        }
                    }
                    if (viewType == ViewType.Bar)
                    {
                        XYDiagram diagram = chart.Diagram as XYDiagram;
                        //diagram.AxisX.Label.Angle =45;
                        diagram.AxisX.Label.MaxLineCount = 20;
                        diagram.AxisX.Label.MaxWidth = 12;
                    }
                }
                rpt.Bands[BandKind.Detail].Controls.Add(chart);
            }      
            return rpt;
        }
    }
}
